#pragma once
#include <iostream>
#include "Socket.hpp"
#include "epoll.hpp"
#include "Connection.hpp"
using namespace EpollModule;

using connection_t = std::shared_ptr<Connection>;

class epollserver
{
    const static int event_num = 64;

private:
    bool IsConnectionExists(int sockfd) // 判断连接是否存在
    {
        return _connects.find(sockfd) != _connects.end();
    }

public:
    epollserver() : _using(false),
                    _epoll(std::make_unique<epoll>())
    {
        _epoll->Init();
    }
    void InserConnction(connection_t &conn) // 插入连接
    {
        auto iter = _connects.find(conn->Sockfd());
        if (iter == _connects.end())
        {
            // 没有就把它放到connects里面管理
            _connects.insert(std::make_pair(conn->Sockfd(), conn));
            // 2. 把新插入进来的连接，写透到内核的epoll中
            _epoll->Ctrl(conn->Sockfd(), conn->GetEvents());
        }
    }
    //基于事件驱动的事件派发器
    void DisPatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sockfd = _event[i].data.fd;
            uint32_t event = _event[i].events;
            if ((event & EPOLLERR) || (event & EPOLLHUP))
                event = (EPOLLIN | EPOLLOUT); // 异常事件，转换成为读写事件
            if ((event & EPOLLIN) && IsConnectionExists(sockfd))
                _connects[sockfd]->CallRecv();
            if ((event & EPOLLOUT) && IsConnectionExists(sockfd))
                _connects[sockfd]->CalSend();
        }
    }

    void LoopOnce(int timeout)
    {
        int n = _epoll->wait(event_num, _event, timeout);
        DisPatcher(n);
    }

    void Lop() // 轮询
    {
        _using = true;
        int timeout = -1;
        while (_using)
        {
            LoopOnce(timeout);
        }
        _using = false;
    }

    void Stop() // 停止
    {
        _using = false;
    }
    ~epollserver()
    {
    }

private:
    std::unique_ptr<epoll> _epoll;                   // 记得不要忘记初始化
    std::unordered_map<int, connection_t> _connects; // 服务器内所有的连接
    bool _using;                                     // 是否正在使用
    struct epoll_event _event[event_num];            // epoll
};
